package com.lzh.gulimall.seckill.config;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;

/**
 * @ClassName RabbitMQConfig
 * @Description TODO
 * @Author liuzhihui
 * @Date 2020/9/3 1:17
 * @Version 1.0
 **/
@Configuration
public class RabbitMQConfig {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 使用json序列化机制，进行消息转换
     * @return
     */
    @Bean
    public MessageConverter messageConverter(){
        return new Jackson2JsonMessageConverter();
    }

    /**
     * 定制RabbitTemplate
     * 1、服务器broker收到消息就回调
     *      1.spring.rabbitmq.publisher-confirm-type=correlated ##开启发送端确认，消息到达broker进行确认
     *      2.设置确认回调ConfirmCallback方法
     *2、消息正确抵达队列进行回调
     *      1.spring.rabbitmq.publisher-returns=true ##开启发送端确认,消息从broker抵达队列的确认
     *        spring.rabbitmq.template.mandatory=true ##只要抵达队列，以异步模式，优先回调returnsConfirm
     *3.消费端确认(保证每个消息被正确消息，此时才可以broker删除这个消息)
     *      1.默认是自动确认的，只要消息接收到，客户端会自动确认，服务端就会移除这个消息
     *      问题：
     *         消费端收到很多消息，自动回复给服务器ack,服务器就删除了消息,但是在处理消息的过程中，消费端宕机了，
     *         可能只处理成功一个消息，其他全丢失了。
     *         解决：手动确认模式。只要我们没有明确告诉MQ。消息被消费，没有Ack给服务端,消息就一直是unacked状态。
     *         即使消费端宕机，消息也不会丢失，会重新变为ready状态，下一次有新的服务端连接进来就发给它
     *      2.如何签收消息
     *          channel.basicAck(deliveryTag, false);签收消息；业务成功完成，就应该签收
     *          channel.basicNack(deliveryTag,false,true);拒签消息；业务失败，就拒签
     *
     */
    //@PostConstruct：当前类的构造器执行完后，执行这个方法
//    @PostConstruct
//    public void initRabbitTemplate(){
//        //设置消息抵达broker回调
//        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
//            /**
//             * 触发时机：只要消息抵达Broker,消息服务器，ack=true
//             * @param correlationData 当前消息的唯一关联数据（这个是消息的唯一id）
//             * @param ack 消息是否成功收到
//             * @param cause 失败的原因
//             */
//            @Override
//            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
//                System.out.println("correlationData["+correlationData+"]==>ack["+ack+"]==>cause["+cause+"]");
//            }
//        });
//
//        //设置消息抵达队列回调
//        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
//            /**
//             * 触发时机：只要消息没有投递给指定的队列，就触发失败回调
//             * 比如：客户端发送消息时，指定的路由键，对不上绑定关系中的路由键，
//             *      那么会在交换机发送消息到队列的过程中，由于没有一个绑定关系上的路由键能匹配
//             *      肯定会发送失败
//             * @param message 投递失败的消息的详细信息
//             * @param replyCode 回复的状态码
//             * @param replyText 回复的内容
//             * @param exchange 当时这个消息发给哪个交换机
//             * @param routingKey 当时这个消息的路由键
//             */
//            @Override
//            public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
//                String messageId = (String) message.getMessageProperties().getHeaders().get("spring_returned_message_correlation");
//                System.out.println("Fail Message["+messageId+"]==>replyCode["+replyCode+"]==>exchange["+exchange+"]==>routingKey["+routingKey+"]");
//            }
//        });
//    }

}
